package org.example.controller.flow.service;

import com.fasterxml.jackson.annotation.ObjectIdGenerators;
import org.example.controller.flow.CompleteTaskVo;
import org.example.controller.flow.FlowNodeVo;
import org.example.controller.flow.HighLightedNodeVo;
import org.example.vo.ReturnVo;
import org.flowable.bpmn.constants.BpmnXMLConstants;
import org.flowable.bpmn.model.*;
import org.flowable.bpmn.model.Process;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.impl.persistence.deploy.ProcessDefinitionCacheEntry;
import org.flowable.engine.impl.persistence.entity.ActivityInstanceEntity;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.ActivityInstance;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.DelegationState;
import org.flowable.task.api.Task;
import org.flowable.task.api.TaskQuery;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class FlowService {

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    RepositoryService repositoryService;

    @Autowired
    HistoryService historyService;


    @Autowired
    IdentityService identityService;
    

    @Autowired
    private TaskService taskService;

    // 启动流程
    public ReturnVo<ProcessInstance> startFlow(String processDefinitionKey,String username){

        // 查询流程定义是否可用
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionKey(processDefinitionKey)
                .latestVersion().singleResult();
        if (processDefinition != null && processDefinition.isSuspended()) {
            ReturnVo returnVo = new ReturnVo<>("500", "此流程已经挂起,请联系系统管理员!");
            return returnVo;
        }
        // 设置启动人
        identityService.setAuthenticatedUserId(username);

        // 启动流程
        Map map = new HashMap();
        map.put("startUser",username);
        map.put("skip","tru");
        //设置自动跳过
        map.put("_FLOWABLE_SKIP_EXPRESSION_ENABLED",true);

        ProcessInstance processInstance = runtimeService.createProcessInstanceBuilder()
                .processDefinitionKey(processDefinitionKey.trim())
                .name("请假了")
                .businessKey(UUID.randomUUID().toString())
                .variables(map)
                .start();
        // tianjialiuchengxinxi
        return new ReturnVo("200","ok",processInstance.getId());
    }

    // 获取当前任务节点
    public ReturnVo<String> getNowTask(String proInstanceId){
        TaskQuery taskQuery = taskService.createTaskQuery().active().processInstanceId(proInstanceId);
        List<Task> list = taskQuery.list();
        String s = "";
        for (Task task : list) {
            s += task.getAssignee()+"----"+task.getName() +"---"+task.getId();
        }
        return new ReturnVo<>("200","ok","taskId  "+s);
    }

    public ReturnVo<String> complete(CompleteTaskVo completeTaskVo){
        // 添加意见
        Task task = taskService.createTaskQuery().taskId(completeTaskVo.getTaskId()).singleResult();
        System.out.printf("t"+ task.getName() +"--------"+ task.getAssignee());
        if (DelegationState.PENDING.equals(task.getDelegationState())){
            Task subTask = this.createSubTask((TaskEntity) task, task.getParentTaskId(), completeTaskVo.getUser());
            taskService.complete(subTask.getId());
            taskService.resolveTask(completeTaskVo.getTaskId(), completeTaskVo.getVariables());
        } else {
            if (completeTaskVo.getVariables() != null) {
                taskService.complete(completeTaskVo.getTaskId(), completeTaskVo.getVariables());
            } else {
                taskService.complete(completeTaskVo.getTaskId());
            }
        }
        return new ReturnVo<>("200","ok","proInsID"+task.getProcessInstanceId());
    }

    // 获取流程图
    // 直接从历史表中查出高亮节点和高亮线，返回给前端
//    private HighLightedNodeVo findHighLightedNodeVoByProcessInstanceId(String processInstanceId) {
//        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
//        List<String> activeActivityIds = new ArrayList<>();
//        List<String> highLightedFlows = new ArrayList<>();
//        List<HistoricActivityInstance> historicSquenceFlows = historyService.createHistoricActivityInstanceQuery()
//                .processInstanceId(processInstanceId).activityType(BpmnXMLConstants.ELEMENT_SEQUENCE_FLOW).list();
//        historicSquenceFlows.forEach(historicActivityInstance -> highLightedFlows.add(historicActivityInstance.getActivityId()));
//        String processDefinitionId = null;
//        String modelName = null;
//        if (processInstance == null) {
//            // 如果流程已经结束了
//            List<HistoricActivityInstance> historicEnds = historyService.createHistoricActivityInstanceQuery()
//                    .processInstanceId(processInstanceId).activityType(BpmnXMLConstants.ELEMENT_EVENT_END).list();
//            List<String> finalActiveActivityIds = activeActivityIds;
//            historicEnds.forEach(historicActivityInstance -> finalActiveActivityIds.add(historicActivityInstance.getActivityId()));
//        } else {
//            processDefinitionId = processInstance.getProcessDefinitionId();
//            activeActivityIds = runtimeService.getActiveActivityIds(processInstanceId);
//            modelName = processInstance.getName();
//        }
//        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
//        byte[] bpmnXML = modelService.getBpmnXML(bpmnModel);
//        String modelXml = new String(bpmnXML, StandardCharsets.UTF_8);
//        return new HighLightedNodeVo(highLightedFlows, activeActivityIds, modelXml, modelName);
//    }

    // 流程定义的挂起激活
    public Boolean susORActiveDefinition(String definition){
        repositoryService.suspendProcessDefinitionById(definition);
        // 挂起后所有流程都不能使用
        repositoryService.activateProcessDefinitionById(definition);
        return true;
    }
    // 流程实例的挂起激活
    public Boolean susORActiveProcess(String processInstanceId){
        runtimeService.suspendProcessInstanceById(processInstanceId);
        runtimeService.activateProcessInstanceById(processInstanceId);
        return true;
    }



    // 流程实例的终止
    public Boolean stopProcess(String processInstanceId){
        // 获取end节点
        BpmnModel bpmnModel = null;
        ProcessInstance subPprocessInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
        bpmnModel = repositoryService.getBpmnModel(subPprocessInstance.getProcessDefinitionId());
        List<EndEvent> disActivitys = null;
        List<String> executionIds = new ArrayList<>();
        if (bpmnModel != null) {
            Process process = bpmnModel.getMainProcess();
            disActivitys = process.findFlowElementsOfType(EndEvent.class);
        }
        String distFilwElementId = disActivitys.get(0).getId();


        List<Execution> executions = runtimeService.createExecutionQuery().parentId(processInstanceId).list();
        executions.forEach(execution -> executionIds.add(execution.getId()));
        runtimeService.createChangeActivityStateBuilder()
                .moveExecutionsToSingleActivityId(executionIds, distFilwElementId)
                .changeState();
        return true;
    }

    // 撤回 其实就是节点的跳转

    // 转办  自己不办理，转交给其他人
    public Boolean turnProcess(String processInstanceId,String assignee){
        Task ptask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
        // 生成历史记录
        if (ptask != null){
            Task subTask = this.createSubTask((TaskEntity) ptask, ptask.getParentTaskId(), assignee);
            taskService.saveTask(subTask);
            // 添加审批意见
            taskService.complete(subTask.getId());
        }
        // 转办
        taskService.setAssignee(ptask.getId(),"王五");
        taskService.setOwner(ptask.getId(),assignee);
        return true;
    }

    // 委派  自己不办理，转交给其他人，再转交给自己
    public Boolean delegation(String processInstanceId,String assignee){
        Task ptask = taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
        // 添加审批意见
        // 设置审批人就是当前登陆人
        taskService.setAssignee(ptask.getId(),assignee);
        // 执行委派
        taskService.delegateTask(ptask.getId(),"王五");

        return true;
    }

    /**
     * 创建任务
     *
     * @param assignee 任务的执行者
     * @param ptask    父亲任务实体
     * @param ptaskId  父亲id
     * @return
     */
    private Task createSubTask(TaskEntity ptask, String ptaskId, String assignee) {
        TaskEntity task = null;
        if (ptask != null){
            task = (TaskEntity) taskService.newTask(UUID.randomUUID().toString());
            task.setAssignee(assignee);
            task.setProcessInstanceId(ptask.getProcessInstanceId());
            task.setProcessDefinitionId(ptask.getProcessDefinitionId());
            task.setParentTaskId(ptaskId);
            task.setCategory(ptask.getCategory());
            task.setDescription(ptask.getDescription());
            task.setName(ptask.getName());
            task.setTaskDefinitionKey(ptask.getTaskDefinitionKey());
            task.setTaskDefinitionId(ptask.getTaskDefinitionId());
            task.setTenantId(ptask.getTenantId());
            task.setCreateTime(new Date());
            task.setPriority(ptask.getPriority());
            taskService.saveTask(task);
        }
        return task;
    }


    // 获取回退的节点
    public List<FlowNodeVo> getBackNodesByProcessInstanceId(String processInstanceId) {
        List<FlowNodeVo> backNods = new ArrayList<>();
        TaskEntity taskEntity = (TaskEntity) taskService.createTaskQuery().processInstanceId(processInstanceId).singleResult();
        String currActId = taskEntity.getTaskDefinitionKey();
        //获取运行节点表中usertask
        String sql = "select t.* from act_ru_actinst t where t.ACT_TYPE_ = 'userTask' " +
                " and t.PROC_INST_ID_=#{processInstanceId} and t.END_TIME_ is not null ";
        List<ActivityInstance> activityInstances = runtimeService.createNativeActivityInstanceQuery().sql(sql)
                .parameter("processInstanceId", processInstanceId)
                .list();
        //获取运行节点表的parallelGateway节点并出重
        sql = "SELECT t.ID_, t.REV_,t.PROC_DEF_ID_,t.PROC_INST_ID_,t.EXECUTION_ID_,t.ACT_ID_, t.TASK_ID_, t.CALL_PROC_INST_ID_, t.ACT_NAME_, t.ACT_TYPE_, " +
                " t.ASSIGNEE_, t.START_TIME_, max(t.END_TIME_) as END_TIME_, t.DURATION_, t.DELETE_REASON_, t.TENANT_ID_" +
                " FROM  act_ru_actinst t WHERE t.ACT_TYPE_ = 'parallelGateway' AND t.PROC_INST_ID_ = #{processInstanceId} and t.END_TIME_ is not null" +
                " and t.ACT_ID_ <> #{actId} GROUP BY t.act_id_";
        List<ActivityInstance> parallelGatewaies = runtimeService.createNativeActivityInstanceQuery().sql(sql)
                .parameter("processInstanceId", processInstanceId)
                .parameter("actId", currActId)
                .list();
        //排序
        if (parallelGatewaies != null && parallelGatewaies.size() > 0) {
            activityInstances.addAll(parallelGatewaies);
            activityInstances.sort(Comparator.comparing(ActivityInstance::getEndTime));
        }
        //分组节点 把并行网关中的用户任务和用户任务分离出来
        int count = 0;
        Map<ActivityInstance, List<ActivityInstance>> parallelGatewayUserTasks = new HashMap<>();
        List<ActivityInstance> userTasks = new ArrayList<>();
        ActivityInstance currActivityInstance = null;
        for (ActivityInstance activityInstance : activityInstances) {
            if (BpmnXMLConstants.ELEMENT_GATEWAY_PARALLEL.equals(activityInstance.getActivityType())) {
                count++;
                if (count % 2 != 0) {
                    List<ActivityInstance> datas = new ArrayList<>();
                    currActivityInstance = activityInstance;
                    parallelGatewayUserTasks.put(currActivityInstance, datas);
                }
            }
            if (BpmnXMLConstants.ELEMENT_TASK_USER.equals(activityInstance.getActivityType())) {
                if (count % 2 == 0) {
                    userTasks.add(activityInstance);
                } else {
                    if (parallelGatewayUserTasks.containsKey(currActivityInstance)) {
                        parallelGatewayUserTasks.get(currActivityInstance).add(activityInstance);
                    }
                }
            }
        }

        List<FlowNodeVo> flowNodeVoList = new ArrayList<>();
        //组装人员
        for (ActivityInstance userTask : userTasks) {
            FlowNodeVo flowNodeVo = new FlowNodeVo();
            flowNodeVo.setNodeId(userTask.getActivityId());
            flowNodeVo.setNodeName(userTask.getActivityName());
            flowNodeVo.setUserName(userTask.getAssignee());
            flowNodeVo.setEndTime(userTask.getEndTime());
            flowNodeVoList.add(flowNodeVo);
        }
        // 组装会签人员
        parallelGatewayUserTasks.forEach((activity, activities) -> {
            FlowNodeVo node = new FlowNodeVo();
            node.setNodeId(activity.getActivityId());
            node.setEndTime(activity.getEndTime());
            StringBuffer nodeNames = new StringBuffer("会签:");
            StringBuffer userNames = new StringBuffer("审批人员:");
            if (activities != null) {
                activities.forEach(activityInstance -> {
                    nodeNames.append(activityInstance.getActivityName()).append(",");
                    userNames.append(activityInstance.getAssignee()).append(",");
                });
                node.setNodeName(nodeNames.toString());
                node.setUserName(userNames.toString());
                flowNodeVoList.add(node);
            }
        });

        //去重合并
        List<FlowNodeVo> datas = flowNodeVoList.stream().collect(
                Collectors.collectingAndThen(Collectors.toCollection(() ->
                        new TreeSet<>(Comparator.comparing(nodeVo -> nodeVo.getNodeId()))), ArrayList::new));

        //排序
        datas.sort(Comparator.comparing(FlowNodeVo::getEndTime));
        return datas;
    }

    // 驳回
    public ReturnVo<String> backToStepTask(String taskId,String username,String toStep) {

        TaskEntity taskEntity = (TaskEntity) taskService.createTaskQuery().taskId(taskId).singleResult();

        //2.设置审批人
        taskEntity.setAssignee(username);
        taskService.saveTask(taskEntity);
        //3.添加驳回意见
        // 执行驳回提交人
        FlowNode distActivity = this.findFlowNodeByActivityId(taskEntity.getProcessDefinitionId(),toStep);
        if ("创建申请".equals(distActivity.getName())){
            ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(taskEntity.getProcessInstanceId()).singleResult();
            runtimeService.setVariable(taskEntity.getProcessInstanceId(), "startUser", processInstance.getStartUserId());
        }
        this.deleteActivity(toStep, taskEntity.getProcessInstanceId());

        List<String> executionIds = new ArrayList<>();
        //6.判断节点是不是子流程内部的节点
        if (this.checkActivitySubprocessByActivityId(taskEntity.getProcessDefinitionId(),
                toStep)
                && this.checkActivitySubprocessByActivityId(taskEntity.getProcessDefinitionId(),
                taskEntity.getTaskDefinitionKey())) {
            //6.1 子流程内部驳回
            Execution executionTask = runtimeService.createExecutionQuery().executionId(taskEntity.getExecutionId()).singleResult();
            String parentId = executionTask.getParentId();
            List<Execution> executions = runtimeService.createExecutionQuery().parentId(parentId).list();
            executions.forEach(execution -> executionIds.add(execution.getId()));
            this.moveExecutionsToSingleActivityId(executionIds, toStep);
        } else {
            //6.2 普通驳回
            List<Execution> executions = runtimeService.createExecutionQuery().parentId(taskEntity.getProcessInstanceId()).list();
            executions.forEach(execution -> executionIds.add(execution.getId()));
            this.moveExecutionsToSingleActivityId(executionIds, toStep);
        }
        return new ReturnVo<>();
    }

    /**
     * 执行跳转
     */
    protected void moveExecutionsToSingleActivityId(List<String> executionIds, String activityId) {
        runtimeService.createChangeActivityStateBuilder()
                .moveExecutionsToSingleActivityId(executionIds, activityId)
                .changeState();
    }


    // 判断是不是子流程节点
    public boolean checkActivitySubprocessByActivityId(String processDefId, String activityId) {
        boolean flag = true;
        List<FlowNode> activities = this.findFlowNodesByActivityId(processDefId,activityId);
        if (activities.size() > 0){
            flag = false;
        }
        return flag;
    }

    public List<FlowNode> findFlowNodesByActivityId(String processDefId, String activityId) {
        List<FlowNode> activities = new ArrayList<>();
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefId);
        List<Process> processes = bpmnModel.getProcesses();
        for (Process process : processes) {
            FlowElement flowElement = process.getFlowElement(activityId);
            if (flowElement != null) {
                FlowNode flowNode = (FlowNode) flowElement;
                activities.add(flowNode);
            }
        }
        return activities;
    }

    public FlowNode findFlowNodeByActivityId(String processDefId, String activityId) {
        FlowNode activity = null;
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefId);
        List<Process> processes = bpmnModel.getProcesses();
        for (Process process : processes){
            FlowElement flowElement = process.getFlowElementMap().get(activityId);
            if (flowElement != null) {
                activity = (FlowNode) flowElement;
                break;
            }
        }
        return activity;
    }

    @Autowired
    ManagementService managementService;

    /**
     * 删除跳转的历史节点信息
     *
     * @param disActivityId     跳转的节点id
     * @param processInstanceId 流程实例id
     */
    protected void deleteActivity(String disActivityId, String processInstanceId) {
        String tableName = managementService.getTableName(ActivityInstanceEntity.class);
        String sql = "select t.* from " + tableName + " t where t.PROC_INST_ID_=#{processInstanceId} and t.ACT_ID_ = #{disActivityId} " +
                " order by t.END_TIME_ ASC";
        List<ActivityInstance> disActivities = runtimeService.createNativeActivityInstanceQuery().sql(sql)
                .parameter("processInstanceId", processInstanceId)
                .parameter("disActivityId", disActivityId).list();
        //删除运行时和历史节点信息
        if (disActivities != null) {
            ActivityInstance activityInstance = disActivities.get(0);
            sql = "select t.* from " + tableName + " t where t.PROC_INST_ID_=#{processInstanceId} and (t.END_TIME_ >= #{endTime} or t.END_TIME_ is null)";
            List<ActivityInstance> datas = runtimeService.createNativeActivityInstanceQuery().sql(sql).parameter("processInstanceId", processInstanceId)
                    .parameter("endTime", activityInstance.getEndTime()).list();
            List<String> runActivityIds = new ArrayList<>();
            if (datas != null) {
                datas.forEach(ai -> runActivityIds.add(ai.getId()));
                // 执行sql进行删除
//                runFlowableActinstDao.deleteRunActinstsByIds(runActivityIds);
//                hisFlowableActinstDao.deleteHisActinstsByIds(runActivityIds);
            }
        }
    }

}
